﻿// FileManagerDlg.cpp: 实现文件
//

#include "pch.h"
#include "FileManagerApp.h"
#include "FileManagerDlg.h"
#include "afxdialogex.h"
#include <string>
#include <thread>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

using namespace std;

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
public:
//    afx_msg void OnTimer(UINT_PTR nIDEvent);
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
//    ON_WM_TIMER()
END_MESSAGE_MAP()

static std::string CString2String(CString str)
{
    std::string strResult;
    int nLen = WideCharToMultiByte(CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
    char* pElementText = new char[nLen + 1];
    WideCharToMultiByte(CP_ACP, 0, str, -1, pElementText, nLen, NULL, NULL);
    strResult = pElementText;
    delete[] pElementText;
    return strResult;
}

static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
{
    if (uMsg == BFFM_INITIALIZED)
    {
        SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
    }

    return 0;
}


// CFileManagerDlg 对话框



CFileManagerDlg::CFileManagerDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_FILEMANAGER_DIALOG, pParent)
    , m_hFileMgr(this)
    , m_hTreeRoot(NULL)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CFileManagerDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_EDIT_PATH, m_editWorkPath);
    DDX_Control(pDX, IDC_TREE_LOCAL, m_treeLocal);
    DDX_Control(pDX, IDC_TREE_DEVICE, m_treeDevice);
    DDX_Control(pDX, IDC_EDIT_DISKINFO, m_editDiskInfo);
    DDX_Control(pDX, IDC_CMB_SERIAL, m_cmbSerial);
    DDX_Control(pDX, IDC_BTN_SERIAL_OPEN, m_btnSerial);
    DDX_Control(pDX, IDC_CMB_BAUDRATE, m_cmbBaudRate);
    DDX_Control(pDX, IDC_BTN_DOWNLOAD, m_btnDLoad);
}

BEGIN_MESSAGE_MAP(CFileManagerDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BTN_LOADPATH, &CFileManagerDlg::OnBnClickedBtnLoadPath)
    ON_BN_CLICKED(IDC_BTN_SYNC_DEVFILE, &CFileManagerDlg::OnBnClickedBtnConnect)
    ON_BN_CLICKED(IDC_BTN_DEL_DEVFILE, &CFileManagerDlg::OnBnClickedBtnDeleteFile)
    ON_BN_CLICKED(IDC_BTN_DOWNLOAD, &CFileManagerDlg::OnBnClickedBtnDownload)
    ON_WM_TIMER()
    ON_BN_CLICKED(IDC_BTN_SERIAL_OPEN, &CFileManagerDlg::OnClickedBtnSerialOpen)
    ON_WM_CLOSE()
    ON_BN_CLICKED(IDC_BTN_DEVMKFS, &CFileManagerDlg::OnBnClickedBtnDiskFormat)
    ON_BN_CLICKED(IDC_BTN_GET_FILELIST, &CFileManagerDlg::OnBnClickedBtnGetFiles)
END_MESSAGE_MAP()


// CFileManagerDlg 消息处理程序

BOOL CFileManagerDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
// 	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
// 	ASSERT(IDM_ABOUTBOX < 0xF000);
// 
// 	CMenu* pSysMenu = GetSystemMenu(FALSE);
// 	if (pSysMenu != nullptr)
// 	{
// 		BOOL bNameValid;
// 		CString strAboutMenu;
// 		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
// 		ASSERT(bNameValid);
// 		if (!strAboutMenu.IsEmpty())
// 		{
// 			pSysMenu->AppendMenu(MF_SEPARATOR);
// 			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
// 		}
// 	}

	// 设置此对话框的图标。  当应用程序主窗口不是对话框时，框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);     // 设置大图标
	SetIcon(m_hIcon, FALSE);    // 设置小图标

	// TODO: 在此添加额外的初始化代码
    SetWindowText(L"HeartBoard Tools");

    m_strSerial = L"COM1";
    m_strRootPath = L"E:\\ElecDIY\\HeartBoard\\TileMaps\\hms";
    m_editWorkPath.SetWindowText(m_strRootPath);

    m_btnDLoad.EnableWindow(FALSE);
    m_editDiskInfo.SetWindowText(L"-/-");

    m_treeLocal.DeleteAllItems();
    m_treeDevice.DeleteAllItems();
    m_treeDevice.InsertItem(L"0:/");
    m_treeDevice.InsertItem(L"1:/");
    //Test
    OnInsert("0:/13", 0);
    OnInsert("1:/13/2344/5578.jpg", 0);
    OnInsert("1:/13/2345/5578.jpg", 0);
    OnInsert("1:/15/4645/12786.jpg", 0);

    m_cmbBaudRate.InsertString(0, L"9600");
    m_cmbBaudRate.InsertString(1, L"38400");
    m_cmbBaudRate.InsertString(2, L"115200");
    m_cmbBaudRate.InsertString(3, L"380400");
    m_cmbBaudRate.InsertString(4, L"921600");
    m_cmbBaudRate.SetCurSel(2);

    SetTimer((UINT_PTR)1, 1000, NULL);
    //KillTimer(1);

    return TRUE;  // 除非将焦点设置到控件，否则返回 TRUE
}

void CFileManagerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮，则需要下面的代码
//  来绘制该图标。  对于使用文档/视图模型的 MFC 应用程序，
//  这将由框架自动完成。

void CFileManagerDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CFileManagerDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CFileManagerDlg::OnClose()
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    KillTimer(1);

    __super::OnClose();
}

void CFileManagerDlg::OnTimer(UINT_PTR nIDEvent)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    if (nIDEvent == 1)
    {
        EnumSerialPort();
    }

    __super::OnTimer(nIDEvent);
}

bool CFileManagerDlg::EnumSerialPort()
{
    HKEY    hKey;
    wchar_t portName[256], commName[256];
    // 打开串口注册表对应的键值  
    if (ERROR_SUCCESS == ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Hardware\\DeviceMap\\SerialComm", NULL, KEY_READ, &hKey))
    {
        int i = 0;
        int mm = 0;
        DWORD  dwLong, dwSize;
        m_cmbSerial.ResetContent();
        while (TRUE)
        {
            dwLong = sizeof(portName)/sizeof(portName[0]);
            dwSize = sizeof(commName)/sizeof(commName[0]);
            // 枚举串口
            if (ERROR_NO_MORE_ITEMS == ::RegEnumValue(hKey, i, portName, &dwLong, NULL, NULL, (PUCHAR)commName, &dwSize))
            {
                break;
            }
            m_cmbSerial.InsertString(-1, commName);
            if (commName == m_strSerial)
            {
                m_cmbSerial.SetCurSel(i);
                mm = 1;
            }
            i++;
        }

        if (mm == 0)
        {
            if (i)
            {
                m_cmbSerial.SetCurSel(0);
                m_cmbSerial.GetLBText(0, m_strSerial);
            }
            else
            {
                m_cmbSerial.SetCurSel(-1);
                m_strSerial = L"";
            }
        }
        // 关闭注册表
        RegCloseKey(hKey);
    }

    return true;
}

CString CFileManagerDlg::GetLocalPath(HTREEITEM hItem)
{
    if (hItem == m_treeLocal.GetRootItem())
        return L".";

    CString strPath = GetLocalPath(m_treeLocal.GetParentItem(hItem)) + L"\\" + m_treeLocal.GetItemText(hItem);
    return strPath;
}

CString CFileManagerDlg::GetDevicePath(HTREEITEM hItem)
{
    if (hItem == NULL || hItem == m_treeDevice.GetRootItem())
        return m_treeDevice.GetItemText(hItem);

    CString strPath;
    if (m_treeDevice.GetParentItem(hItem))
    {
        strPath = GetDevicePath(m_treeDevice.GetParentItem(hItem));

        if (strPath.Right(1) != L"/")
            strPath += L"/";
        strPath += m_treeDevice.GetItemText(hItem);
    }
    else
    {
        strPath = m_treeDevice.GetItemText(hItem);
    }
    return strPath;
}

bool CFileManagerDlg::LoadDirFiles(HTREEITEM hParent, CString strPath)
{
    HTREEITEM hChild = hParent;// m_treeLocal.GetChildItem(hParent);
    while (hChild)
    {
        if (strPath.Right(1) != "\\")                   //从右边1开始获取从右向左nCount个字符
            strPath += _T("\\");
        strPath += "*.*";
        //将当前目录下文件枚举并InsertItem树状显示
        CFileFind file;
        BOOL bContinue = file.FindFile(strPath);
        while (bContinue)
        {
            bContinue = file.FindNextFile();
            if (file.IsDirectory() && !file.IsDots())   //找到文件为内容且不为点"."
            {
                CString strPath = file.GetFileName();
                HTREEITEM hSubChild= m_treeLocal.InsertItem(strPath, hChild);
                LoadDirFiles(hSubChild, file.GetFilePath());
            }
            else if (!file.IsDirectory())                           //找到文件不为内容
            {
                CString strPath = file.GetFileName();
                m_treeLocal.InsertItem(strPath, hChild);  //添加盘符路径下树状文件
            }
        }
        hChild = m_treeLocal.GetNextItem(hChild, TVGN_NEXT);    //获取树形控件TVGN_NEXT下兄弟项
    }

    return true;
}

// bool CFileManagerDlg::LoadFileList()
// {
//     HTREEITEM hNext = m_treeLocal.GetRootItem();
//     while (hNext)
//     {
//         CString strText = m_treeLocal.GetItemText(hNext);   //检索列表中项目文字
//         if (strText.Right(1) != "\\")                   //从右边1开始获取从右向左nCount个字符
//             strText += _T("\\");
//         strText += "*.*";
//         //将当前目录下文件枚举并InsertItem树状显示
//         CFileFind file;                                 //定义本地文件查找
//         BOOL bContinue = file.FindFile(strText);        //查找包含字符串的文件
//         while (bContinue)
//         {
//             bContinue = file.FindNextFile();            //查找下一个文件
//             if (file.IsDirectory() && !file.IsDots())   //找到文件为内容且不为点"."
//             {
//                 CString strPath = file.GetFileName();
//                 HTREEITEM hChild = m_treeLocal.InsertItem(strPath, hNext); //添加盘符路径下树状文件夹
//                 LoadDirFiles(hChild, file.GetFilePath());                               //递归调用
//             }
//             else if (!file.IsDirectory())                           //找到文件不为内容
//             {
//                 CString strPath = file.GetFileName();
//                 m_treeLocal.InsertItem(strPath, hNext);  //添加盘符路径下树状文件
//             }
//         }
//         hNext = m_treeLocal.GetNextItem(hNext, TVGN_NEXT);    //获取树形控件TVGN_NEXT下兄弟项
//     }
// 
//     return true;
// }

bool CFileManagerDlg::InsertDevFile(HTREEITEM hParent, CString strPath)
{
    int nPos = strPath.Find(L"/", 0);
    if (nPos >= 0)
    {
        CString strTemp = strPath.Left(nPos);
        HTREEITEM hNext = m_treeDevice.GetChildItem(hParent);
        while (hNext)
        {
            CString strTree = m_treeDevice.GetItemText(hNext);
            if (strTree == strTemp)
            {
                //next level
                strPath = strPath.Mid(nPos + 1, strPath.GetLength());
                InsertDevFile(hNext, strPath);
                return true;
            }
            hNext = m_treeDevice.GetNextItem(hNext, TVGN_NEXT);
        }

        //目录不存在，新增
        m_treeDevice.InsertItem(strTemp, hParent);
        InsertDevFile(hParent, strPath);
    }
    else if (strPath.GetLength() > 0)
    {
        m_treeDevice.InsertItem(strPath, hParent);
    }

    return true;
}

void CFileManagerDlg::DelAllChildOfItem(HTREEITEM hItem)
{
    BOOL bRet = FALSE;
    HTREEITEM hChildItem = NULL;
    while (TRUE)
    {
        bRet = m_treeDevice.ItemHasChildren(hItem);
        if (!bRet)//没有孩子
        {
            break;
        }
        else
        {
            hChildItem = m_treeDevice.GetChildItem(hItem);
            DelAllChildOfItem(hChildItem);
            m_treeDevice.DeleteItem(hChildItem);
        }
    }
}

void CFileManagerDlg::OnInsert(const char* strName, bool bIsDir)
{
    CString strPath = CString(strName);
    int nPos = strPath.Find(L":/", 0); //example: 0:/*.* or 1:/*.*
    if (nPos >= 0)
    {
        HTREEITEM hNext = m_treeDevice.GetRootItem();
        CString strTemp = strPath.Left(nPos + 2);
        while (hNext)
        {
            CString strTree = m_treeDevice.GetItemText(hNext);
            if (strTree == strTemp)
            {
                strPath = strPath.Mid(nPos + 2, strPath.GetLength());
                InsertDevFile(hNext, strPath);
                break;
            }
            hNext = m_treeDevice.GetNextItem(hNext, TVGN_NEXT);
        }
    }
    m_treeDevice.Expand(m_treeDevice.GetRootItem(), TVE_EXPAND);
}

void CFileManagerDlg::OnDiskInfo(int iDiskId, uint32_t uTotal, uint32_t uFreex)
{
    CString strInfo;
    CString strText;

    if (iDiskId >= 0 && iDiskId < DISK_MAX_NUM)
    {
        m_uDiskTotal[iDiskId] = uTotal;
        m_uDiskFree[iDiskId] = uFreex;
    }
    for (auto i = 0; i < DISK_MAX_NUM; i++)
    {
        strText.Format(L"Part1:%dkB/%dkB %.2fUsed\r\n", m_uDiskFree[i], m_uDiskTotal[i], 100.0 * m_uDiskFree[i] / m_uDiskFree[i]);
        strInfo += strText;
    }

    m_editDiskInfo.SetWindowText(strInfo);
}

void CFileManagerDlg::OnBnClickedBtnLoadPath()
{
    // TODO: 在此添加控件通知处理程序代码CString dir;
    TCHAR       szFolderPath[MAX_PATH] = { 0 };
    BROWSEINFO  sInfo;
    ::ZeroMemory(&sInfo, sizeof(BROWSEINFO));
    sInfo.pidlRoot = 0;
    sInfo.lpszTitle = _T("请选择路径");
    sInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_EDITBOX | BIF_DONTGOBELOWDOMAIN;
    sInfo.lParam = (LPARAM)(m_strRootPath.GetBuffer(m_strRootPath.GetLength()));//初始化路径，形如(_T("C:\\"));
    sInfo.lpfn = BrowseCallbackProc;

    // 显示文件夹选择对话框  
    LPITEMIDLIST lpidlBrowse = ::SHBrowseForFolder(&sInfo);
    if (lpidlBrowse != NULL)
    {
        // 取得文件夹名  
        if (::SHGetPathFromIDList(lpidlBrowse, szFolderPath))
        {
            char szPath[MAX_PATH] = { 0 };
            m_strRootPath = szFolderPath;
            m_editWorkPath.SetWindowText(m_strRootPath);
            m_treeLocal.DeleteAllItems();
            m_treeLocal.InsertItem(m_strRootPath);
            LoadDirFiles(m_treeLocal.GetRootItem(), m_strRootPath);
            m_treeLocal.Expand(m_treeLocal.GetRootItem(), TVE_EXPAND);
            m_hFileMgr.LoadFile(CString2String(m_strRootPath + L"\\"));
        }
        ::CoTaskMemFree(lpidlBrowse);
    }
}

void CFileManagerDlg::OnBnClickedBtnDownload()
{
    // TODO: 在此添加控件通知处理程序代码
    HTREEITEM hCurTree = m_treeLocal.GetSelectedItem();//获得当前选中ID
    if (hCurTree == NULL)
    {
        AfxMessageBox(L"Please select a lcoal file or folder!");
        return;
    }
    CString strLocalPath = GetLocalPath(hCurTree);//获得当前选中文本
    strLocalPath = strLocalPath.Right(strLocalPath.GetLength() - 2);

    hCurTree = m_treeDevice.GetSelectedItem();//获得当前选中ID
    if (hCurTree == NULL)
    {
        AfxMessageBox(L"Please select a root folder at device!");
        return;
    }

    CString strDevicePath = GetDevicePath(hCurTree).Left(3);//获得当前选中文本
    assert(strDevicePath == L"0:/" || strDevicePath == L"1:/");

    m_btnDLoad.EnableWindow(FALSE);
    m_hFileMgr.Transmit(CString2String(strLocalPath).c_str(), CString2String(strDevicePath).c_str());
    m_btnDLoad.EnableWindow(TRUE);

    CString strText;
    UINT uSendCnt, uFailCnt;
    m_hFileMgr.GetTranState(uSendCnt, uFailCnt);
    strText.Format(L"Fail:%d Toatl:%d", uFailCnt, uSendCnt);
    MessageBox(strText, L"Warnning");
}


void CFileManagerDlg::OnBnClickedBtnConnect()
{
    // TODO: 在此添加控件通知处理程序代码
    m_hFileMgr.Connect("");
}

void CFileManagerDlg::OnBnClickedBtnGetFiles()
{
    // TODO: 在此添加控件通知处理程序代码
    HTREEITEM hCurTree = m_treeDevice.GetSelectedItem();//获得当前选中ID
    if (hCurTree == NULL)
    {
        AfxMessageBox(L"Please select a root folder at device!");
        return;
    }

    CString strDevicePath = GetDevicePath(hCurTree).Left(3);//获得当前选中文本
    assert(strDevicePath == L"0:/" || strDevicePath == L"1:/");

    while (m_treeDevice.GetParentItem(hCurTree) != NULL)
        hCurTree = m_treeDevice.GetParentItem(hCurTree);

    if (strDevicePath == L"0:/" || strDevicePath == L"1:/")
    {
        DelAllChildOfItem(hCurTree);

        m_hFileMgr.GetFiles(CString2String(strDevicePath).c_str());
    }
}

void CFileManagerDlg::OnBnClickedBtnDeleteFile()
{
    // TODO: 在此添加控件通知处理程序代码
    HTREEITEM hCurTree = m_treeDevice.GetSelectedItem();//获得当前选中ID
    if (hCurTree == NULL)
    {
        AfxMessageBox(L"Please select a file at device!");
        return;
    }
    CString strText = GetDevicePath(hCurTree);//获得当前选中文本

    m_hFileMgr.RemoveFile(CString2String(strText).c_str());
}


void CFileManagerDlg::OnClickedBtnSerialOpen()
{
    // TODO: 在此添加控件通知处理程序代码
    CString strBtnText;
    m_btnSerial.GetWindowText(strBtnText);

    if (strBtnText == L"Open")
    {
        UINT32 nBaudRate = 115200;
        int  nSel = m_cmbSerial.GetCurSel();
        if (nSel == -1)
        {
            AfxMessageBox(L"Please select a serial port!");
            return;
        }
        m_cmbSerial.GetLBText(nSel, m_strSerial);

        nSel = m_cmbBaudRate.GetCurSel();
        if (nSel >=0)
        {
            m_cmbBaudRate.GetLBText(nSel, strBtnText);
            nBaudRate = _ttoi(strBtnText);
        }

        m_btnDLoad.EnableWindow(TRUE);
        m_btnSerial.SetWindowText(L"Close");

        m_hFileMgr.OpenSerial(CString2String(m_strSerial).c_str(), nBaudRate);
    }
    else if (strBtnText == L"Close")
    {
        m_btnDLoad.EnableWindow(FALSE);
        m_btnSerial.SetWindowText(L"Open");
        m_hFileMgr.CloseSerial();
    }
}

void CFileManagerDlg::OnBnClickedBtnDiskFormat()
{
    // TODO: 在此添加控件通知处理程序代码

    HTREEITEM hCurTree = m_treeDevice.GetSelectedItem();//获得当前选中ID
    if (hCurTree == NULL)
    {
        AfxMessageBox(L"Please select a root folder at device!");
        return;
    }

    UINT retval = MessageBox(_T("确定要格式化该分区吗？"), _T("警告！"), MB_YESNO | MB_ICONQUESTION);
    if (retval == IDYES) {
        // 如果用户点击“是”，则执行相关代码
        CString strDevicePath = GetDevicePath(hCurTree);//获得当前选中文本
        strDevicePath = strDevicePath.Left(3);

        m_hFileMgr.FormatDisk(CString2String(strDevicePath).c_str());
    }
}


